package cqrtplm.aop;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.hustcad.plm.pdm.common.model.vo.BusinessObjectVO;
import com.hustcad.plm.pdm.common.model.vo.iteration.CommonIteratorVO;
import com.hustcad.plm.pdm.iba.model.dto.SaveIBAInputDTO;
import com.hustcad.plm.pdm.iba.model.dto.SaveObjIBADTO;
import com.hustcad.plm.pdm.iba.service.TyplmAttributeValueService;
import com.hustcad.plm.pdm.lifestage.model.vo.LifeCycleStageVO;
import com.hustcad.plm.pdm.lifestage.service.TyplmLifecycleStageService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.dto.constraint.IbaDTO;
import com.ty.basic.entity.CTyEntityBaseDO;
import com.ty.basic.response.ResponseResult;
import com.ty.basic.vo.AttributeVO;
import cqrtplm.constant.RTErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author fxw
 * @version 1.0
 * @className DocumentLogicAOP
 * @description 文档逻辑AOP
 * @since 2025/11/3 15:51
 */
@Aspect
@Component
@Slf4j
public class DocumentLogicAOP {

    private static final String DOC_TYPE_NAME = "ty.inteplm.doc.CTyDoc";
    private static final String CHANGE_POLICY = "Change";
    private static final String CADDOC_TYPE_NAME = TableTypeConstrant.TY_CADDOC_OTYPE;
    private static final char STAGE_B = 'B';
    private static final String BUSINESS_EDITION_KEY = "BusinessEdition";
    private static final String STAGE_KEY = "Stage";
    private static final Pattern PATTERN = Pattern.compile("[A-Za-z](\\d+)");

    @Resource
    private TyplmAttributeValueService typlmAttributeValueService;
    @Resource
    private TyplmLifecycleStageService typlmLifecycleStageService;

    @Around(value = "execution(* com.hustcad.plm.pdm.iteration.controller.TyplmIterationController.batchNewVersionWithPolicy(..))")
    public Object documentRevisionPolicy(ProceedingJoinPoint point) throws Throwable {
        Object result = point.getArgs()[0];
        if (!(result instanceof List)) {
            return point.proceed();
        }

        @SuppressWarnings("unchecked") List<CommonIteratorVO> list = (List<CommonIteratorVO>) result;
        if (list.isEmpty()) {
            return point.proceed();
        }

        for (CommonIteratorVO commonIteratorVO : list) {
            BigInteger id = Convert.toBigInteger(commonIteratorVO.getId());
            String typeName = commonIteratorVO.getTypeDefName();

            List<LifeCycleStageVO> optionalLifeCycleStages = typlmLifecycleStageService.getOptionalLifeCycleStages(id,
                                                                                                                   typeName);
            if (optionalLifeCycleStages == null || optionalLifeCycleStages.isEmpty()) {
                continue;
            }

            log.debug("Lifecycle stages: {}", JSON.toJSONString(optionalLifeCycleStages));

            boolean isDoc = (DOC_TYPE_NAME.equals(typeName) || typeName.equals(
                    CADDOC_TYPE_NAME));

            if (isDoc && CHANGE_POLICY.equals(commonIteratorVO.getChangePolicy())) {
                Map<String, List<AttributeVO>> stage = typlmAttributeValueService.getIbaAttrValueByOidAndKeys(
                        Collections.singletonList(id), typeName, Collections.singletonList(STAGE_KEY));

                List<AttributeVO> attributeList = stage.get(id.toString());
                if (attributeList != null && !attributeList.isEmpty()) {
                    AttributeVO attributeStageVO = attributeList.get(0);
                    if (attributeStageVO != null && !StrUtil.isEmpty(attributeStageVO.getAttributeValue())) {
                        String value = attributeStageVO.getAttributeValue();
                        if (!value.isEmpty() && value.charAt(0) == STAGE_B) {
                            throw RTErrorCodeEnum.STATUS_INFO_CONTENT_IS_NULL.getException("B阶段不允许修订");
                        }
                    }
                }
            }
        }

        return point.proceed();
    }

    @AfterReturning(value = "execution(* com.hustcad.plm.pdm.iteration.controller.TyplmIterationController.batchNewVersionWithPolicy(..))", returning = "returnValue")
    public void afterBatchNewVersion(Object returnValue) {
        if (!(returnValue instanceof ResponseResult) || !((ResponseResult<?>) returnValue).isSuccess()) {
            return;
        }

        @SuppressWarnings("unchecked") List<BusinessObjectVO> returnValue1 = (List<BusinessObjectVO>) ((ResponseResult<?>) returnValue).getData();

        if (returnValue1 == null || returnValue1.isEmpty()) {
            return;
        }

        returnValue1.forEach(businessObjectVO -> {
            if (businessObjectVO.getOtype().equals(DOC_TYPE_NAME) ||
                    businessObjectVO.getOtype().equals(TableTypeConstrant.TY_CADDOC_OTYPE)) {
                BigInteger id = businessObjectVO.getId();
                String typeDefName = businessObjectVO.getOtype();

                Map<String, List<AttributeVO>> businessEditionMap = typlmAttributeValueService.getIbaAttrValueByOidAndKeys(
                        Collections.singletonList(id), typeDefName, Collections.singletonList(BUSINESS_EDITION_KEY));

                List<AttributeVO> attributeList = businessEditionMap.get(id.toString());
                if (attributeList != null && !attributeList.isEmpty()) {
                    AttributeVO attributeStageVO = attributeList.get(0);
                    if (attributeStageVO != null && !StrUtil.isEmpty(attributeStageVO.getAttributeValue())) {
                        String businessEdition = attributeStageVO.getAttributeValue();
                        if (!businessEdition.isEmpty() && businessEdition.charAt(0) != STAGE_B) {
                            updateBusinessEdition(id, typeDefName, businessEdition);
                        }
                    }
                }
                removeChangeAttributes(id, businessObjectVO.getOtype());
            }
        });
    }

    private void updateBusinessEdition(BigInteger id, String typeDefName, String businessEdition) {
        Matcher matcher = PATTERN.matcher(businessEdition);
        if (matcher.matches()) {
            try {
                int value = Integer.parseInt(matcher.group(1));
                int newValue = value + 1;
                String updatedBusinessEdition = businessEdition.replaceFirst("\\d+", String.valueOf(newValue));

                IbaDTO ibaDTO = new IbaDTO();
                ibaDTO.setKey(BUSINESS_EDITION_KEY);
                ibaDTO.setValue(updatedBusinessEdition);

                SaveIBAInputDTO saveIBAInputDTO = new SaveIBAInputDTO();
                saveIBAInputDTO.setPartAtts(Collections.singletonList(ibaDTO));
                typlmAttributeValueService.batchSaveIBAAttributeValues(saveIBAInputDTO,
                                                                       new CTyEntityBaseDO(id, typeDefName), false);
            } catch (NumberFormatException e) {
                log.warn("Failed to parse business edition number: {}", businessEdition, e);
            }
        }
    }

    private void removeChangeAttributes(BigInteger id, String otype) {
        List<IbaDTO> partAtts = new ArrayList<>();
        partAtts.add(createIbaDTO("ChangeDocumentNumber"));
        partAtts.add(createIbaDTO("ChangeDescription"));

        SaveObjIBADTO saveIBAInputDTO = new SaveObjIBADTO();
        saveIBAInputDTO.setObjIbaList(partAtts);
        saveIBAInputDTO.setCTyEntityBaseDO(new CTyEntityBaseDO(id, otype));

        typlmAttributeValueService.batchSaveIBAByObjList(Collections.singletonList(saveIBAInputDTO), false);
    }

    private IbaDTO createIbaDTO(String key) {
        IbaDTO ibaDTO = new IbaDTO();
        ibaDTO.setKey(key);
        ibaDTO.setValue(" ");
        ibaDTO.setIsNeedCheck("N");
        return ibaDTO;
    }
}
